package com.zm.springcloudsentinel.controller;

import com.alibaba.csp.sentinel.AsyncEntry;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphO;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.zm.springcloudsentinel.service.AsyncService;
import com.zm.springcloudsentinel.util.SentinelExceptionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


/**
 * 多种资源定义方式
 */
@RequestMapping("/def")
@RestController
public class ResourceDefineController {


    /**
     * 一、调用接口时 ， sentinel会自动定义资源并显示在dashboard上 ， 默认资源名为接口路径
     */



    /**
     * 二、注解定义资源
     * 1. 注解不加value时 ： dashboard识别的资源名为默认的接口路径名/def/ano ,以及dashboard从注解上识别的全路径方法名com.zm.sentinelnacos.handler.ResourceDefineController:ano()
     * 2. 注解中value与dashboard识别到的接口路径名相同时 ， dashboard就只显示这一个资源名
     * 3. 注解中的value与dashboard识别到的接口路径名不同时 ， dashboard会显示两个资源名
     */
    @SentinelResource
    @RequestMapping("/ano1")
    public String ano1(){
        return "注解定义资源1";
    }
    @SentinelResource(value = "/def/ano2")
    @RequestMapping("/ano2")
    public String ano2(){
        return "注解定义资源2";
    }
    @SentinelResource(value = "ano3")
    @RequestMapping("/ano3")
    public String ano3(){
        return "注解定义资源3";
    }

    /**
     * 三、代码内定义资源
     */
    @RequestMapping("/code1")
    public String code1(){
        // 1.5.0 版本开始可以利用 try-with-resources 特性
        // 资源名可使用任意有业务语义的字符串，比如方法名、接口名或其它可唯一标识的字符串。
        try (Entry entry = SphU.entry("code1")) {
            // 被保护的业务逻辑
            // do something here...
            return "代码定义资源";
        } catch (BlockException ex) {
            // 资源访问阻止，被限流或被降级
            // 在此处进行相应的处理操作
            String s = SentinelExceptionUtil.exceptionType(ex);
            return "代码定义资源被-"+s;
        }
    }

    /**
     * 返回布尔类型判断是否被限流或降级
     * @return
     */
    @RequestMapping("/code2")
    public String code2(){
        // 资源名可使用任意有业务语义的字符串
        if (SphO.entry("code2")) {
            // 务必保证finally会被执行
            try {
                /**
                 * 被保护的业务逻辑
                 */
                return "代码定义资源-返回布尔：true";
            } finally {
                SphO.exit();
            }
        } else {
            // 资源访问阻止，被限流或被降级
            // 进行相应的处理操作
            return "代码定义资源被限流/降级-返回布尔：false";
        }
    }

    /**
     * 异步
     * Sentinel 支持异步调用链路的统计。在异步调用中，需要通过 SphU.asyncEntry(xxx) 方法定义资源，并通常需要在异步的回调函数中调用 exit 方法。以下是一个简单的示例：
     */
    @Autowired
    private AsyncService asyncService;
    @RequestMapping("/code3")
    public void code3(){
        AsyncEntry entry=null;
        try {
            entry = SphU.asyncEntry("code3");
            asyncService.doAsync();
            // 异步调用.
        } catch (BlockException ex) {
            // Request blocked.
            // Handle the exception (e.g. retry or fallback).
            String s = SentinelExceptionUtil.exceptionType(ex);
            System.err.println("代码定义资源被-"+s);
        }finally {
            if(entry!=null){
                entry.exit();
            }
        }
    }



}
